Skip to content

perf(pharmacy): optimize transfer request item add — DTOs, single rate query, AJAX#21089

Merged
buddhika75 merged 6 commits into
developmentfrom
21062-transfer-request-dto-optimization
Jun 2, 2026
Merged

perf(pharmacy): optimize transfer request item add — DTOs, single rate query, AJAX#21089
buddhika75 merged 6 commits into
developmentfrom
21062-transfer-request-dto-optimization

Conversation

@buddhika75
Copy link
Copy Markdown
Member

@buddhika75 buddhika75 commented May 31, 2026

Summary

  • Replace full Item entity loads in the transfer request autocomplete with lightweight ItemDTO projections (4 typed constructor queries per keystroke instead of 1 full entity query)
  • Replace 3 separate entity-loading rate calls on item select with a single BillItemFinanceDetails scalar query via new ItemRatesDTO
  • Change the Add Item button from ajax=false (full page reload) to AJAX with targeted component updates
  • Eliminate N+1 on the edit path by adding JOIN FETCH bi.item and LEFT JOIN FETCH bi.billItemFinanceDetails to fetchBillItems
  • Fix brittle bi.item.class eq 'class com.divudi...' comparison that silently broke for Hibernate proxies in edit mode (now uses class.simpleName, and correctly handles Vmpp which was missing)
  • Cache three department-type display lists (previously recomputed from config lookups on every render)
  • Fetch institution eagerly in recentToDepartments query to prevent lazy load in processTransferRequest

New files

File Purpose
core/data/dto/ItemRatesDTO.java Holds purchase/retail/cost from one query
core/converter/ItemDtoConverter.java CDI converter for autocomplete DTO round-trip

DB calls reduced per item-add cycle

Event Before After
Per autocomplete keystroke 1 × full entity query (up to 30 objects) 4 × DTO projection queries
On item select 3 × full BillItem entity loads for rates 1 × itemFacade.find + 1 × scalar rates query
Add Item click Full page reload AJAX — updates itemList + requestTotals only
Edit path bill items load 1 + N lazy SELECTs (N = item count) 1 query with JOIN FETCH

Navigation path for QA testing

  1. Pharmacy → Disbursement → Transfer Request
  2. Select a target department
  3. Type at least 3 characters in the Item field — verify the autocomplete shows Name / Code / Type / Pack Size columns correctly for Amp, Ampp, Vmp, and Vmpp items
  4. Select an item — verify rates populate in the rate/value fields (if enabled via config)
  5. Enter a quantity and click Add Item — verify the item appears in the table without a full page reload, pack size column shows correctly
  6. Navigate to an existing saved request via the finalize list and click Edit — verify all items display correctly with correct pack sizes (this exercises the fetchBillItems JOIN FETCH path)
  7. Remove an item from the table — verify totals update correctly

Related issues created

Closes #21062

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

Summary by CodeRabbit

  • New Features

    • DTO-based autocomplete for transfer requests and a UI converter for item selections.
    • New rate bundle object exposing purchase/retail/cost rates.
  • Improvements

    • Item selection now populates rates and pack sizing from DTOs; AJAX add-item flow and pack-size display updated.
    • Reduced lazy-loading by eager-fetching related bill/item data; more reliable recent-department lookups.
  • Bug Fixes

    • Bill-level finance totals are reset correctly during transfer calculations.
  • Chores

    • Persistence units updated to explicit JTA datasource names.

…e query, AJAX add

Replace full Item entity loads in pharmacy_transfer_request.xhtml with
lightweight DTOs and a single-query rate lookup, eliminating the main
sources of delay when adding items to a transfer request.

Changes:
- ItemDTO (search): add dblValue, itemTypeName, rateItemId fields +
  new constructor for autocomplete DTO queries
- ItemRatesDTO (new): holds purchase/retail/cost rates from one query
- ItemDtoConverter (new): CDI converter encodes DTO as id:type:dblValue:rateItemId
- ItemController: add completeAmpAmppVmpVmppItemDtosForRequestingDepartment
  returning List<ItemDTO> via 4 typed constructor queries (replaces full
  entity load per keystroke)
- PharmacyBean: add getLastRatesForItem replacing 3 separate entity-loading
  rate calls with a single BillItemFinanceDetails scalar query
- TransferRequestController: autocomplete now uses ItemDTO + typed proxy;
  populateRatesOnItemSelect reduced from 3 entity loads to 1 entity load +
  1 scalar query; addItem reuses cached rates; fetchBillItems adds
  JOIN FETCH bi.item and LEFT JOIN FETCH bi.billItemFinanceDetails to
  eliminate N+1 on edit path; recentToDepartments query fetches institution
  eagerly; three display type list getters are now lazily cached
- XHTML: autocomplete bound to currentItemDto with itemDtoConverter;
  Add Item button changed from ajax=false (full page reload) to AJAX with
  targeted updates; pack-size column uses class.simpleName instead of
  brittle full class string comparison (also fixes Vmpp display)

Closes #21062

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 31, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 00fb4940-dbcf-4928-8d30-7545ed5359e4

📥 Commits

Reviewing files that changed from the base of the PR and between 784dd4d and 7626b44.

📒 Files selected for processing (1)
  • src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml

Walkthrough

Refactors transfer-request item selection to use ItemDTO and ItemRatesDTO: adds DTO models and converter, backend DTO autocomplete and rate lookup, integrates DTOs into TransferRequestController for selection and rate population, updates JSF autocomplete binding and AJAX add-item flow, and includes small finance/defaults and persistence datasource fixes.

Changes

Transfer Request DTO-driven Item Selection and Rates

Layer / File(s) Summary
DTO Models and Serialization
src/main/java/com/divudi/core/data/dto/search/ItemDTO.java, src/main/java/com/divudi/core/data/dto/ItemRatesDTO.java, src/main/java/com/divudi/core/converter/ItemDtoConverter.java
ItemDTO extended with dblValue, itemTypeName, and rateItemId; new ItemRatesDTO holds purchase/retail/cost rates; ItemDtoConverter provides JSF serialization/deserialization for colon-delimited DTO strings.
Backend Query Services
src/main/java/com/divudi/bean/common/ItemController.java, src/main/java/com/divudi/ejb/PharmacyBean.java
ItemController.completeAmpAmppVmpVmppItemDtosForRequestingDepartment implements config-aware autocomplete via four ItemDTO constructor JPQL queries, aggregation, sort, and max-results cap; PharmacyBean.getLastRatesForItem returns ItemRatesDTO using a costing-aware single-query path or department-fallback lookups; stock-history type resolution helper added.
TransferRequestController DTO Integration
src/main/java/com/divudi/bean/pharmacy/TransferRequestController.java
Adds currentItemDto, currentItemRates, cached dept-type label lists, and accessors; autocomplete now delegates to ItemController returning ItemDTO; addItem and populateRatesOnItemSelect use currentItemRates (or fallback) and compute pack/unit from DTO type name to populate PharmaceuticalBillItem and BillItemFinanceDetails; fetchBillItems join-fetches item and finance details; recreate and department-change handlers clear DTOs and caches; recent-to-departments query now returns distinct Department with institution.
UI Layer: Autocomplete and Form Submission
src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml
Autocomplete input bound to transferRequestController.currentItemDto with itemDtoConverter; pack-size rendering computed from dblValue or bi.item.class.simpleName with numeric default 1; Add Item button changed to AJAX submit with explicit process/update targets and focus handling.
Small fixes & config
src/main/java/com/divudi/bean/pharmacy/TransferIssueForRequestsController.java, src/main/java/com/divudi/bean/pharmacy/TransferReceiveController.java, src/main/resources/META-INF/persistence.xml
Zeroes bill-level finance totals during transfer-issue/receive calculations and sets explicit JTA data-source JNDI names for persistence units (jdbc/coop, jdbc/ruhunuAudit).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

  • #20995 — Similar entity→DTO autocomplete and re-fetch-on-select rate population pattern implemented elsewhere.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive While most changes directly address the performance objective, modifications to persistence.xml datasource configuration and fixes to unrelated data-quality issues (stockhistory.historyType, billfinancedetails totals) appear tangential to the stated transfer-request item-add optimization goal. Clarify whether persistence.xml datasource hardcoding and collateral data-quality fixes should be in a separate PR, or confirm they are necessary dependencies for the transfer-request optimization.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: performance optimization in the pharmacy transfer request item-add workflow using DTOs, single rate query, and AJAX.
Linked Issues check ✅ Passed The PR fully addresses issue #21062 by implementing DTO-based autocomplete projections, consolidating rate lookups into single queries, switching Add Item to AJAX, and removing N+1 queries on edit.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 21062-transfer-request-dto-optimization

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 47c7acbb60

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml (2)

176-178: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove txtLineCostRate from the AJAX update targets (src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml:176-178)

txtLineCostRate is referenced in the p:ajax update list, but no component with id="txtLineCostRate" exists in this view, so the AJAX update target can’t be resolved.

Suggested fix
                                             <p:ajax event="itemSelect"
                                                     listener="#{transferRequestController.populateRatesOnItemSelect}"
-                                                    update="txtLineCostRate txtLineGrossRate txtLineNetValue requestTotals focusQty selDepartmentType"/>
+                                                    update="txtLineGrossRate txtLineNetValue requestTotals focusQty selDepartmentType"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml` around lines 176 -
178, Remove the non-existent AJAX update target by editing the p:ajax in
pharmacy_transfer_request.xhtml: locate the p:ajax with listener
"#{transferRequestController.populateRatesOnItemSelect}" and remove
"txtLineCostRate" from its update list so the remaining update targets (e.g.,
txtLineGrossRate, txtLineNetValue, requestTotals, focusQty, selDepartmentType)
are valid.

211-217: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Narrow the AJAX process scope for “Add Item”. (src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml:211-217)

process="@Form" causes the whole <h:form> (including the editable p:dataTable id="itemList" rows) to be decoded/validated on every add, so latency will scale with row count.

<p:commandButton
    value="Add Item"
    icon="fas fa-plus"
    class="ui-button-success w-100"
    action="#{transferRequestController.addItem}"
    process="`@form`"
    update="itemAutoComplete txtQty txtLineGrossRate txtLineNetValue itemList requestTotals focusItem"/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml` around lines 211 -
217, The Add Item button currently uses process="`@form`" which decodes/validates
the entire h:form (including the editable p:dataTable id="itemList"); change the
p:commandButton's process attribute to only submit the specific input components
needed for addItem (for example use "`@this` itemAutoComplete txtQty
txtLineGrossRate txtLineNetValue" or similar) and remove "`@form`" so the
controller method addItem and validations only run for those inputs while
leaving update="itemList requestTotals focusItem" unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml`:
- Around line 171-174: The Pack Size column is showing vt.dblValue for any
positive number; update the EL in the h:outputText so dblValue is used only when
the item type is Ampp or Vmpp. Replace the current condition "(vt.dblValue ne
null and vt.dblValue gt 0) ? vt.dblValue : 1" with a compound check that also
ensures the DTO's item-type field (e.g., vt.itemType or the actual property
holding the item type) is 'Ampp' or 'Vmpp' before using vt.dblValue, otherwise
default to 1; keep the <f:convertNumber> formatting unchanged.

---

Outside diff comments:
In `@src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml`:
- Around line 176-178: Remove the non-existent AJAX update target by editing the
p:ajax in pharmacy_transfer_request.xhtml: locate the p:ajax with listener
"#{transferRequestController.populateRatesOnItemSelect}" and remove
"txtLineCostRate" from its update list so the remaining update targets (e.g.,
txtLineGrossRate, txtLineNetValue, requestTotals, focusQty, selDepartmentType)
are valid.
- Around line 211-217: The Add Item button currently uses process="`@form`" which
decodes/validates the entire h:form (including the editable p:dataTable
id="itemList"); change the p:commandButton's process attribute to only submit
the specific input components needed for addItem (for example use "`@this`
itemAutoComplete txtQty txtLineGrossRate txtLineNetValue" or similar) and remove
"`@form`" so the controller method addItem and validations only run for those
inputs while leaving update="itemList requestTotals focusItem" unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b552135-72c7-4aca-8a5c-90e31c302b8d

📥 Commits

Reviewing files that changed from the base of the PR and between fefeaa1 and 47c7acb.

📒 Files selected for processing (7)
  • src/main/java/com/divudi/bean/common/ItemController.java
  • src/main/java/com/divudi/bean/pharmacy/TransferRequestController.java
  • src/main/java/com/divudi/core/converter/ItemDtoConverter.java
  • src/main/java/com/divudi/core/data/dto/ItemRatesDTO.java
  • src/main/java/com/divudi/core/data/dto/search/ItemDTO.java
  • src/main/java/com/divudi/ejb/PharmacyBean.java
  • src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml

Comment thread src/main/webapp/pharmacy/pharmacy_transfer_request.xhtml
buddhika75 and others added 3 commits June 2, 2026 06:02
…is.git into development

# Conflicts:
#	src/main/webapp/dataAdmin/admin_functions.xhtml

Signed-off-by: buddhika <buddhika.ari@gmail.com>
… StockHistory historyType for transfer bills

- TransferIssueForRequestsController: set billNetTotal and billGrossTotal to ZERO in
  calculateBillTotalsForTransferIssue — these were NULL causing incomplete BFD records
- TransferReceiveController: same fix in the receive bill finance population block
- PharmacyBean: add resolveStockHistoryType() helper and call it from both
  addToStockHistory overloads so StockHistory.historyType is never NULL

Related: #21062
Closes #21156 (pbi/bifd value sign issue tracked separately)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@buddhika75
Copy link
Copy Markdown
Member Author

Fix pushed — commit 784dd4de6d

Three data-quality issues found during investigation of transfer TI/COOP/26/000277 / OPPHTI/460:

# Table Field(s) Problem Fix
billfinancedetails BILLNETTOTAL, BILLGROSSTOTAL NULL for all transfer issue/receive bills Set to ZERO in calculateBillTotalsForTransferIssue (issue) and the receive finance block
stockhistory HISTORYTYPE NULL for all pharmacy transactions Added resolveStockHistoryType() helper in PharmacyBean; called from both addToStockHistory overloads
📋 pharmaceuticalbillitem / billitemfinancedetails PURCHASEVALUE, RETAILVALUE, COSTVALUE / VALUEAT*RATE Positive values despite negative QTY on issue bills Tracked separately → #21156

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/resources/META-INF/persistence.xml`:
- Line 5: The persistence.xml currently hardcodes JNDI names inside the
<jta-data-source> elements (values "jdbc/coop" and "jdbc/ruhunuAudit"); replace
those hardcoded values with the CI/CD placeholders ${JDBC_DATASOURCE} for the
primary datasource and ${JDBC_AUDIT_DATASOURCE} for the audit datasource so the
pipeline variable checks pass and deployments use environment-specific JNDI
names, ensuring you update both occurrences (the two <jta-data-source> elements)
accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e2944baa-c5ec-4cfb-b72a-525cfb54cae6

📥 Commits

Reviewing files that changed from the base of the PR and between 47c7acb and 784dd4d.

📒 Files selected for processing (4)
  • src/main/java/com/divudi/bean/pharmacy/TransferIssueForRequestsController.java
  • src/main/java/com/divudi/bean/pharmacy/TransferReceiveController.java
  • src/main/java/com/divudi/ejb/PharmacyBean.java
  • src/main/resources/META-INF/persistence.xml
✅ Files skipped from review due to trivial changes (2)
  • src/main/java/com/divudi/bean/pharmacy/TransferReceiveController.java
  • src/main/java/com/divudi/bean/pharmacy/TransferIssueForRequestsController.java

Comment thread src/main/resources/META-INF/persistence.xml Outdated
buddhika75 and others added 2 commits June 3, 2026 04:10
…er request UI (#21089)

- Gate autocomplete pack-size column by item type (Ampp/Vmpp only),
  defaulting to 1 for non-pack items — fixes misleading pack size display
- Add IDs (panelRateInput, panelValueInput) to both conditional h:panelGroup
  wrappers for rate/value inputs; update all AJAX update attributes to target
  the panels instead of the inner component IDs, preventing JSF tree
  resolution failures when rates are hidden by config or privilege

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace hardcoded local JNDI names with required CI/CD variables:
- jdbc/coop → ${JDBC_DATASOURCE}
- jdbc/ruhunuAudit → ${JDBC_AUDIT_DATASOURCE}

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@buddhika75 buddhika75 merged commit 1de03cd into development Jun 2, 2026
3 checks passed
@buddhika75 buddhika75 deleted the 21062-transfer-request-dto-optimization branch June 2, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delay When Adding Items to Transfer Request

1 participant